package com.junqi.live.room.common.annotation;

import com.junqi.common.entity.AjaxResult;
import com.junqi.live.room.common.utils.LoginUtil;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;

/**
 * Description: 分布式锁切面
 */
@Slf4j
@Aspect
@Component
@Order(0)//确保比事务注解先执行，分布式锁在事务外
public class RedissonLockAspect {

    @Autowired
    private RedissonClient redissonClient;

    @Around("@annotation(com.junqi.live.room.common.annotation.RedissonLock)")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        //当前线程名
        String threadName = Thread.currentThread().getName();
        log.info("线程{}------进入分布式锁aop------", threadName);
        Method method = ((MethodSignature) joinPoint.getSignature()).getMethod();
        RedissonLock redissonLock = method.getAnnotation(RedissonLock.class);
        String className = getTargetClassName(joinPoint);

        String methodName = method.getName();

        String loginId = LoginUtil.getLoginId();//用户id

        RLock lock = redissonClient.getLock("rds." +className +"." +methodName+"."+ loginId);
        boolean lockSuccess = lock.tryLock(redissonLock.waitTime(),redissonLock.leaseTime(), TimeUnit.MILLISECONDS);
        if (!lockSuccess) {
            AjaxResult.errorRun("请求太频繁了，请稍后再试哦~~");
        }
        try {
            try {
                Thread.sleep(10000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return joinPoint.proceed();//执行锁内的代码逻辑
        } finally {
            log.info("线程{}------结束分布式锁aop------", threadName);
            if (lock.isLocked() && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    private String getTargetClassName(ProceedingJoinPoint pjp) {
        StringBuffer classBuffer = new StringBuffer();
        String className = pjp.getTarget().getClass().getName();
        String[] clsNames = className.split("\\.");
        for (int i = 0; i < clsNames.length; i++) {
            if (i < clsNames.length - 1) {
                classBuffer.append(clsNames[i].substring(0, 1));
                classBuffer.append(".");
            } else {
                classBuffer.append(clsNames[i]);
            }
        }

        return classBuffer.toString();
    }

}
